/*
 * Copyright (c) 2005-2009 Substance Kirill Grouchnikov. All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions are met:
 * 
 *  o Redistributions of source code must retain the above copyright notice, 
 *    this list of conditions and the following disclaimer. 
 *     
 *  o Redistributions in binary form must reproduce the above copyright notice, 
 *    this list of conditions and the following disclaimer in the documentation 
 *    and/or other materials provided with the distribution. 
 *     
 *  o Neither the name of Substance Kirill Grouchnikov nor the names of 
 *    its contributors may be used to endorse or promote products derived 
 *    from this software without specific prior written permission. 
 *     
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 */
package org.jvnet.substance.skin;

import java.awt.*;
import java.awt.MultipleGradientPaint.CycleMethod;

import javax.swing.JSeparator;

import org.jvnet.substance.api.*;
import org.jvnet.substance.api.SubstanceConstants.ColorShiftKind;
import org.jvnet.substance.painter.border.InnerDelegateBorderPainter;
import org.jvnet.substance.painter.border.StandardBorderPainter;
import org.jvnet.substance.painter.decoration.DecorationAreaType;
import org.jvnet.substance.painter.decoration.SubstanceDecorationPainter;
import org.jvnet.substance.painter.gradient.StandardGradientPainter;
import org.jvnet.substance.painter.highlight.ClassicHighlightPainter;
import org.jvnet.substance.painter.utils.SeparatorPainterUtils;
import org.jvnet.substance.shaper.ClassicButtonShaper;
import org.jvnet.substance.utils.*;

/**
 * <code>Office Blue 2007</code> skin. This class is part of officially
 * supported API.
 * 
 * @author Kirill Grouchnikov
 * @since version 3.1
 */
public class OfficeBlue2007Skin extends SubstanceSkin {
	/**
	 * Display name for <code>this</code> skin.
	 */
	public static final String NAME = "Office Blue 2007";

	/**
	 * Creates a new <code>Office Blue 2007</code> skin.
	 */
	public OfficeBlue2007Skin() {
		SubstanceColorScheme activeScheme = SubstanceColorSchemeUtilities
				.getColorScheme(OfficeBlue2007Skin.class
						.getClassLoader()
						.getResource(
								"org/jvnet/substance/skin/office-blue-active.colorscheme"));
		SubstanceColorScheme defaultScheme = SubstanceColorSchemeUtilities
				.getColorScheme(OfficeBlue2007Skin.class
						.getClassLoader()
						.getResource(
								"org/jvnet/substance/skin/office-blue-default.colorscheme"));

		SubstanceColorSchemeBundle defaultSchemeBundle = new SubstanceColorSchemeBundle(
				activeScheme, defaultScheme, defaultScheme);
		defaultSchemeBundle.registerColorScheme(defaultScheme, 0.5f,
				ComponentState.DISABLED_UNSELECTED);
		defaultSchemeBundle.registerColorScheme(activeScheme, 0.5f,
				ComponentState.DISABLED_SELECTED);

		SubstanceColorScheme rolloverScheme = SubstanceColorSchemeUtilities
				.getColorScheme(OfficeBlue2007Skin.class
						.getClassLoader()
						.getResource(
								"org/jvnet/substance/skin/office-blue-rollover.colorscheme"));
		SubstanceColorScheme rolloverSelectedScheme = SubstanceColorSchemeUtilities
				.getColorScheme(OfficeBlue2007Skin.class
						.getClassLoader()
						.getResource(
								"org/jvnet/substance/skin/office-blue-rollover-selected.colorscheme"));
		SubstanceColorScheme selectedScheme = SubstanceColorSchemeUtilities
				.getColorScheme(OfficeBlue2007Skin.class
						.getClassLoader()
						.getResource(
								"org/jvnet/substance/skin/office-blue-selected.colorscheme"));
		SubstanceColorScheme pressedScheme = SubstanceColorSchemeUtilities
				.getColorScheme(OfficeBlue2007Skin.class
						.getClassLoader()
						.getResource(
								"org/jvnet/substance/skin/office-blue-pressed.colorscheme"));
		SubstanceColorScheme pressedSelectedScheme = SubstanceColorSchemeUtilities
				.getColorScheme(OfficeBlue2007Skin.class
						.getClassLoader()
						.getResource(
								"org/jvnet/substance/skin/office-blue-pressed-selected.colorscheme"));

		// register state-specific color schemes on rollovers and selections
		defaultSchemeBundle.registerColorScheme(rolloverScheme,
				ComponentState.ROLLOVER_UNSELECTED);
		defaultSchemeBundle.registerColorScheme(rolloverSelectedScheme,
				ComponentState.ROLLOVER_SELECTED);
		defaultSchemeBundle.registerColorScheme(selectedScheme,
				ComponentState.SELECTED);
		defaultSchemeBundle.registerColorScheme(pressedScheme,
				ComponentState.PRESSED_UNSELECTED);
		defaultSchemeBundle.registerColorScheme(pressedSelectedScheme,
				ComponentState.PRESSED_SELECTED);

		// register state-specific highlight color schemes on rollover and
		// selections
		defaultSchemeBundle.registerHighlightColorScheme(rolloverScheme, 0.8f,
				ComponentState.ROLLOVER_UNSELECTED);
		defaultSchemeBundle.registerHighlightColorScheme(selectedScheme, 0.8f,
				ComponentState.SELECTED);
		defaultSchemeBundle.registerHighlightColorScheme(
				rolloverSelectedScheme, 0.8f, ComponentState.ROLLOVER_SELECTED);
		defaultSchemeBundle.registerHighlightColorScheme(selectedScheme, 0.8f,
				ComponentState.ARMED, ComponentState.ROLLOVER_ARMED);

		// borders and marks
		SubstanceColorScheme borderDefaultScheme = SubstanceColorSchemeUtilities
				.getColorScheme(OfficeBlue2007Skin.class
						.getClassLoader()
						.getResource(
								"org/jvnet/substance/skin/office-blue-border-default.colorscheme"));
		SubstanceColorScheme borderActiveScheme = SubstanceColorSchemeUtilities
				.getColorScheme(OfficeBlue2007Skin.class
						.getClassLoader()
						.getResource(
								"org/jvnet/substance/skin/office-blue-border-active.colorscheme"));
		SubstanceColorScheme borderRolloverScheme = SubstanceColorSchemeUtilities
				.getColorScheme(OfficeBlue2007Skin.class
						.getClassLoader()
						.getResource(
								"org/jvnet/substance/skin/office-border-rollover.colorscheme"));
		SubstanceColorScheme borderRolloverSelectedScheme = SubstanceColorSchemeUtilities
				.getColorScheme(OfficeBlue2007Skin.class
						.getClassLoader()
						.getResource(
								"org/jvnet/substance/skin/office-border-rollover-selected.colorscheme"));
		SubstanceColorScheme borderSelectedScheme = SubstanceColorSchemeUtilities
				.getColorScheme(OfficeBlue2007Skin.class
						.getClassLoader()
						.getResource(
								"org/jvnet/substance/skin/office-border-selected.colorscheme"));
		SubstanceColorScheme borderPressedScheme = SubstanceColorSchemeUtilities
				.getColorScheme(OfficeBlue2007Skin.class
						.getClassLoader()
						.getResource(
								"org/jvnet/substance/skin/office-border-pressed.colorscheme"));

		defaultSchemeBundle.registerColorScheme(borderDefaultScheme,
				ColorSchemeAssociationKind.BORDER, ComponentState.DEFAULT);
		defaultSchemeBundle.registerColorScheme(borderDefaultScheme,
				ColorSchemeAssociationKind.BORDER,
				ComponentState.DISABLED_SELECTED,
				ComponentState.DISABLED_UNSELECTED);
		defaultSchemeBundle.registerColorScheme(borderActiveScheme,
				ColorSchemeAssociationKind.BORDER, ComponentState.ACTIVE);
		defaultSchemeBundle.registerColorScheme(borderRolloverScheme,
				ColorSchemeAssociationKind.BORDER,
				ComponentState.ROLLOVER_UNSELECTED);
		defaultSchemeBundle.registerColorScheme(borderRolloverSelectedScheme,
				ColorSchemeAssociationKind.BORDER,
				ComponentState.ROLLOVER_SELECTED, ComponentState.ARMED,
				ComponentState.ROLLOVER_ARMED);
		defaultSchemeBundle.registerColorScheme(borderSelectedScheme,
				ColorSchemeAssociationKind.BORDER, ComponentState.SELECTED);
		defaultSchemeBundle.registerColorScheme(borderPressedScheme,
				ColorSchemeAssociationKind.BORDER,
				ComponentState.PRESSED_SELECTED,
				ComponentState.PRESSED_UNSELECTED);

		defaultSchemeBundle.registerColorScheme(borderDefaultScheme,
				ColorSchemeAssociationKind.MARK, ComponentState.DEFAULT);
		defaultSchemeBundle.registerColorScheme(borderDefaultScheme,
				ColorSchemeAssociationKind.MARK,
				ComponentState.DISABLED_SELECTED,
				ComponentState.DISABLED_UNSELECTED);
		defaultSchemeBundle.registerColorScheme(borderActiveScheme,
				ColorSchemeAssociationKind.MARK, ComponentState.ACTIVE);
		defaultSchemeBundle.registerColorScheme(borderRolloverSelectedScheme,
				ColorSchemeAssociationKind.MARK,
				ComponentState.ROLLOVER_SELECTED);
		defaultSchemeBundle.registerColorScheme(borderSelectedScheme,
				ColorSchemeAssociationKind.MARK, ComponentState.SELECTED);
		defaultSchemeBundle.registerColorScheme(borderPressedScheme,
				ColorSchemeAssociationKind.MARK,
				ComponentState.ROLLOVER_UNSELECTED,
				ComponentState.PRESSED_SELECTED,
				ComponentState.PRESSED_UNSELECTED);

		// tabs and tab borders
		SubstanceColorScheme tabSelectedScheme = SubstanceColorSchemeUtilities
				.getColorScheme(OfficeBlue2007Skin.class
						.getClassLoader()
						.getResource(
								"org/jvnet/substance/skin/office-blue-tab-selected.colorscheme"));
		SubstanceColorScheme tabRolloverScheme = SubstanceColorSchemeUtilities
				.getColorScheme(OfficeBlue2007Skin.class
						.getClassLoader()
						.getResource(
								"org/jvnet/substance/skin/office-blue-tab-rollover.colorscheme"));
		defaultSchemeBundle.registerColorScheme(tabSelectedScheme,
				ColorSchemeAssociationKind.TAB, ComponentState.SELECTED,
				ComponentState.ROLLOVER_SELECTED,
				ComponentState.PRESSED_SELECTED,
				ComponentState.PRESSED_UNSELECTED);
		defaultSchemeBundle.registerColorScheme(tabRolloverScheme,
				ColorSchemeAssociationKind.TAB,
				ComponentState.ROLLOVER_UNSELECTED);
		defaultSchemeBundle.registerColorScheme(borderDefaultScheme,
				ColorSchemeAssociationKind.TAB_BORDER, ComponentState.SELECTED,
				ComponentState.ROLLOVER_UNSELECTED);
		defaultSchemeBundle.registerColorScheme(rolloverSelectedScheme,
				ColorSchemeAssociationKind.TAB_BORDER,
				ComponentState.ROLLOVER_SELECTED);

		// separator
		SubstanceColorScheme separatorScheme = SubstanceColorSchemeUtilities
				.getColorScheme(OfficeBlue2007Skin.class
						.getClassLoader()
						.getResource(
								"org/jvnet/substance/skin/office-blue-separator.colorscheme"));
		defaultSchemeBundle.registerColorScheme(separatorScheme,
				ColorSchemeAssociationKind.SEPARATOR);

		this.registerDecorationAreaSchemeBundle(defaultSchemeBundle,
				DecorationAreaType.NONE);

		this.watermarkScheme = SubstanceColorSchemeUtilities
				.getColorScheme(OfficeBlue2007Skin.class
						.getClassLoader()
						.getResource(
								"org/jvnet/substance/skin/office-blue-watermark.colorscheme"));

		SubstanceColorScheme generalWatermarkScheme = SubstanceColorSchemeUtilities
				.getColorScheme(OfficeBlue2007Skin.class
						.getClassLoader()
						.getResource(
								"org/jvnet/substance/skin/office-blue-header-watermark.colorscheme"));

		this.registerAsDecorationArea(generalWatermarkScheme,
				DecorationAreaType.FOOTER, DecorationAreaType.HEADER,
				DecorationAreaType.TOOLBAR);

		SubstanceColorScheme titleWatermarkScheme = SubstanceColorSchemeUtilities
				.getColorScheme(OfficeBlue2007Skin.class
						.getClassLoader()
						.getResource(
								"org/jvnet/substance/skin/office-blue-title-watermark.colorscheme"));

		this.registerAsDecorationArea(titleWatermarkScheme,
				DecorationAreaType.GENERAL,
				DecorationAreaType.PRIMARY_TITLE_PANE,
				DecorationAreaType.SECONDARY_TITLE_PANE);

		setSelectedTabFadeStart(0.7);
		setSelectedTabFadeEnd(0.9);

		this.buttonShaper = new ClassicButtonShaper();
		this.watermark = null;
		this.gradientPainter = new OfficeBlue2007GradientPainter();
		this.decorationPainter = new OfficeBlue2007DecorationPainter();
		this.borderPainter = new OfficeBlue2007BorderPainter();
		this.highlightPainter = new ClassicHighlightPainter();

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.jvnet.substance.skin.SubstanceSkin#getDisplayName()
	 */
	public String getDisplayName() {
		return NAME;
	}

	/**
	 * Custom decoration painter to paint the glossy title panes.
	 * 
	 * @author Kirill Grouchnikov
	 */
	private static class OfficeBlue2007DecorationPainter implements
			SubstanceDecorationPainter {
		/*
		 * (non-Javadoc)
		 * 
		 * @see org.jvnet.substance.utils.SubstanceTrait#getDisplayName()
		 */
		public String getDisplayName() {
			return "Office Blue 2007 Decoration";
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see
		 * org.jvnet.substance.painter.decoration.SubstanceDecorationPainter#
		 * paintDecorationArea(java.awt.Graphics2D, java.awt.Component,
		 * org.jvnet.substance.painter.decoration.DecorationAreaType, int, int,
		 * org.jvnet.substance.skin.SubstanceSkin)
		 */
		public void paintDecorationArea(Graphics2D graphics, Component comp,
				DecorationAreaType decorationAreaType, int width, int height,
				SubstanceSkin skin) {
			switch (decorationAreaType) {
			case PRIMARY_TITLE_PANE:
			case SECONDARY_TITLE_PANE:
				this.paintTitleBackground(graphics, comp, width, height, skin
						.getBackgroundColorScheme(decorationAreaType));
				break;
			default:
				this.paintExtraBackground(graphics, SubstanceCoreUtilities
						.getHeaderParent(comp), comp, width, height, skin
						.getBackgroundColorScheme(decorationAreaType));
			}
		}

		/**
		 * Paints the title background.
		 * 
		 * @param graphics
		 *            Graphics context.
		 * @param comp
		 *            Component.
		 * @param width
		 *            Width.
		 * @param height
		 *            Height.
		 * @param scheme
		 *            Color scheme for painting the title background.
		 */
		private void paintTitleBackground(Graphics2D graphics, Component comp,
				int width, int height, SubstanceColorScheme scheme) {
			Graphics2D g2d = (Graphics2D) graphics.create();
			MultipleGradientPaint gradient = new LinearGradientPaint(0, 0, 0,
					height, new float[] { 0.0f, 0.1199999f, 0.12f, 0.5f, 0.9f,
							1.0f }, new Color[] { scheme.getLightColor(),
							scheme.getLightColor(), scheme.getUltraDarkColor(),
							scheme.getMidColor(), scheme.getUltraLightColor(),
							scheme.getLightColor() }, CycleMethod.REPEAT);
			g2d.setPaint(gradient);

			g2d.fillRect(0, 0, width, height);

			g2d.translate(0, height - 1);
			SeparatorPainterUtils.paintSeparator(comp, g2d, width, 0,
					JSeparator.HORIZONTAL, false, 0);
			g2d.dispose();
		}

		/**
		 * Paints the background of non-title decoration areas.
		 * 
		 * @param graphics
		 *            Graphics context.
		 * @param parent
		 *            Component ancestor for computing the correct offset of the
		 *            background painting.
		 * @param comp
		 *            Component.
		 * @param width
		 *            Width.
		 * @param height
		 *            Height.
		 * @param scheme
		 *            Color scheme for painting the title background.
		 */
		private void paintExtraBackground(Graphics2D graphics,
				Container parent, Component comp, int width, int height,
				SubstanceColorScheme scheme) {
			graphics.setColor(scheme.getMidColor());
			graphics.fillRect(0, 0, width, height);
		}
	}

	/**
	 * Custom border painter.
	 * 
	 * @author Kirill Grouchnikov
	 */
	private static class OfficeBlue2007BorderSinglePainter extends
			StandardBorderPainter {
		@Override
		public String getDisplayName() {
			return "Office Blue 2007 Single Border";
		}

		@Override
		public Color getTopBorderColor(
				SubstanceColorScheme interpolationScheme1,
				SubstanceColorScheme interpolationScheme2, double cycleCoef,
				boolean useCyclePosAsInterpolation) {
			if (!useCyclePosAsInterpolation)
				return interpolationScheme1.getExtraLightColor();
			return new Color(SubstanceColorUtilities.getInterpolatedRGB(
					interpolationScheme1.getExtraLightColor(),
					interpolationScheme2.getExtraLightColor(), cycleCoef));
		}

		@Override
		public Color getMidBorderColor(
				SubstanceColorScheme interpolationScheme1,
				SubstanceColorScheme interpolationScheme2, double cycleCoef,
				boolean useCyclePosAsInterpolation) {
			if (!useCyclePosAsInterpolation)
				return interpolationScheme1.getDarkColor();
			return new Color(SubstanceColorUtilities.getInterpolatedRGB(
					interpolationScheme1.getDarkColor(),
					interpolationScheme2.getDarkColor(), cycleCoef));
		}

		@Override
		public Color getBottomBorderColor(
				SubstanceColorScheme interpolationScheme1,
				SubstanceColorScheme interpolationScheme2, double cycleCoef,
				boolean useCyclePosAsInterpolation) {
			if (!useCyclePosAsInterpolation)
				return interpolationScheme1.getMidColor();
			return new Color(SubstanceColorUtilities.getInterpolatedRGB(
					interpolationScheme1.getMidColor(), interpolationScheme2
							.getMidColor(), cycleCoef));
		}
	}

	/**
	 * Custom border painter.
	 * 
	 * @author Kirill Grouchnikov
	 */
	private static class OfficeBlue2007BorderPainter extends
			InnerDelegateBorderPainter {
		/**
		 * Creates the border painter for the Office Blue 2007 skin.
		 */
		public OfficeBlue2007BorderPainter() {
			super("Office Blue 2007 Border",
					new OfficeBlue2007BorderSinglePainter(), 0.8f,
					ColorShiftKind.TINT);
		}
	}

	/**
	 * Custom gradient painter for the Office Blue 2007 skin.
	 * 
	 * @author Kirill Grouchnikov
	 */
	private class OfficeBlue2007GradientPainter extends StandardGradientPainter {
		@Override
		public Color getTopShineColor(
				SubstanceColorScheme interpolationScheme1,
				SubstanceColorScheme interpolationScheme2, double cycleCoef,
				boolean useCyclePosAsInterpolation) {
			return null;
		}

		@Override
		public Color getBottomShineColor(
				SubstanceColorScheme interpolationScheme1,
				SubstanceColorScheme interpolationScheme2, double cycleCoef,
				boolean useCyclePosAsInterpolation) {
			return null;
		}

		@Override
		public Color getTopFillColor(SubstanceColorScheme interpolationScheme1,
				SubstanceColorScheme interpolationScheme2, double cycleCoef,
				boolean useCyclePosAsInterpolation) {
			if (!useCyclePosAsInterpolation)
				return interpolationScheme1.getUltraLightColor();
			return new Color(SubstanceColorUtilities.getInterpolatedRGB(
					interpolationScheme1.getUltraLightColor(),
					interpolationScheme2.getUltraLightColor(), cycleCoef));
		}

		@Override
		public Color getMidFillColorTop(
				SubstanceColorScheme interpolationScheme1,
				SubstanceColorScheme interpolationScheme2, double cycleCoef,
				boolean useCyclePosAsInterpolation) {
			if (!useCyclePosAsInterpolation)
				return interpolationScheme1.getLightColor();
			return new Color(SubstanceColorUtilities.getInterpolatedRGB(
					interpolationScheme1.getLightColor(), interpolationScheme2
							.getLightColor(), cycleCoef));
		}

		@Override
		public Color getMidFillColorBottom(
				SubstanceColorScheme interpolationScheme1,
				SubstanceColorScheme interpolationScheme2, double cycleCoef,
				boolean useCyclePosAsInterpolation) {
			if (!useCyclePosAsInterpolation)
				return interpolationScheme1.getUltraDarkColor();
			return new Color(SubstanceColorUtilities.getInterpolatedRGB(
					interpolationScheme1.getUltraDarkColor(),
					interpolationScheme2.getUltraDarkColor(), cycleCoef));
		}

		@Override
		public Color getBottomFillColor(
				SubstanceColorScheme interpolationScheme1,
				SubstanceColorScheme interpolationScheme2, double cycleCoef,
				boolean useCyclePosAsInterpolation) {
			if (!useCyclePosAsInterpolation)
				return interpolationScheme1.getExtraLightColor();
			return new Color(SubstanceColorUtilities.getInterpolatedRGB(
					interpolationScheme1.getExtraLightColor(),
					interpolationScheme2.getExtraLightColor(), cycleCoef));
		}
	}

}
